package com.ljf.game.schedule;

import com.ljf.game.WebsocketManager;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 描述 :
 * fixedDelay:控制方法执行的间隔时间，是以上一次方法执行完开始算起，如上一次方法执行阻塞住了，那么直到上一次执行完，并间隔给定的时间后，执行下一次。
 * fixedRate:是按照一定的速率执行，是从上一次方法执行开始的时间算起，如果上一次方法阻塞住了，下一次也是不会执行，但是在阻塞这段时间内累计应该执行的次数，当不再阻塞时，一下子把这些全部执行掉，而后再按照固定速率继续执行。
 * initialDelay：initialDelay = 10000 表示在容器启动后，延迟10秒后再执行一次定时器。
 * <p>
 * 版本     作者     时间      内容
 * 1.0      lijinfeng       2025-05-12 17:48     create
 */
@EnableScheduling   // 1.开启定时任务
@EnableAsync        // 2.开启多线程
@Component
public class HeartBeatSchedule {

    private static Boolean isOpen = false;

    private static volatile ConcurrentHashMap<String, LocalDateTime> existSession = new ConcurrentHashMap<>();

    private static volatile ConcurrentHashMap<String, Integer> timeoutCount = new ConcurrentHashMap<>();

    public static boolean changeStatus() {
        isOpen = !isOpen;
        existSession.clear();
        timeoutCount.clear();
        System.out.println(isOpen);
        return isOpen;
    }

    public static void addExistSession(String username){

        if(!isOpen)
            return;

        System.out.println(LocalDateTime.now().toLocalTime() + " 心跳信息保存：" + username);

        existSession.put(username,LocalDateTime.now());
    }



    /**
     * 超时后移除会话标识，认为断开连接
     */
    @Async
    @Scheduled(fixedDelay = 10 * 1000)  //间隔10秒
    public void heartBeatTimeout() {
        if(!isOpen)
            return;

        if (existSession != null) {
            LocalDateTime now = LocalDateTime.now();
            Iterator<Map.Entry<String, LocalDateTime>> iterator = existSession.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, LocalDateTime> entry = iterator.next();
                LocalDateTime expirationTime = entry.getValue();
                if (expirationTime != null && expirationTime.plusSeconds(10L).isBefore(now)) {
                    System.out.println(now.toLocalTime() + " "+entry.getKey()+"超时");
                    iterator.remove();
                }
            }
        }

    }

    @Async
    @Scheduled(fixedDelay = 2000)
    public void groupHeartBeatCheck() {
        if(!isOpen)
            return;

        ConcurrentHashMap<String, ConcurrentHashMap<String, WebSocketSession>> groupAll = WebsocketManager.groupGetAll();

        groupAll.forEach((groupKey,groupValue) ->{
            // 顺便移除空房间
            if(groupValue.isEmpty()){
                WebsocketManager.groupRemove(groupKey);
            }

            groupValue.forEach((memberKey,memberValue) ->{
                LocalDateTime date = existSession.get(memberKey);
                if (null == date){

                    WebsocketManager.sendMessageToAll(groupValue,new HashMap<>(),memberKey+"断开连接");
                    Integer i = timeoutCount.get(memberKey);
                    System.out.println(i);

                    if(null == i){

                        timeoutCount.put(memberKey,1);
                    }else {
                        // 超过10次，将其移除房间
                        if (i >= 10){
                            WebsocketManager.sendMessageToAll(groupValue,new HashMap<>(),memberKey+"退出了房间");
                            WebsocketManager.groupRemoveOne(groupKey,memberKey);
                            // 超时次数归零
                            timeoutCount.remove(memberKey);
                        }else {
                            timeoutCount.put(memberKey,++i);
                        }
                    }

                }
            });
        });

    }

}
